<!DOCTYPE html>
<html lang="en">
  <head>
    <title>
        Java-framework-Spring-6-AOP - rulerLwx Blog
      </title>
        <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta name="viewport"
      content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no, minimal-ui">
    <meta name="renderer" content="webkit">
    <meta http-equiv="Cache-Control" content="no-transform" />
    <meta http-equiv="Cache-Control" content="no-siteapp" />
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black">
    <meta name="format-detection" content="telephone=no,email=no,adress=no">
    
    <meta name="theme-color" content="#000000" />
    
    <meta http-equiv="window-target" content="_top" />
    
    
    <meta name="description" content="AOP AOP(Aspect Orient Programming)，面向切面编程。 我的理解：把公共的方法抽取出来，大家共用。 Spring默认使用JDK动态代理来创建AOP代理，" />
    <meta name="generator" content="Hugo 0.73.0 with theme pure" />
    <title>Java-framework-Spring-6-AOP - rulerLwx Blog</title>
    
    
    <link rel="stylesheet" href="https://rulerLwx.gitee.io/css/style.min.c4bc7071f132c964c2116bca53b392933f377e5ca7b7051ed245187c621a2d3e.css">
    
    <link rel="stylesheet" href="https://cdn.staticfile.org/highlight.js/9.15.10/styles/github.min.css" async>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/tocbot/4.4.2/tocbot.css" async>
    <meta property="og:title" content="Java-framework-Spring-6-AOP" />
<meta property="og:description" content="AOP AOP(Aspect Orient Programming)，面向切面编程。 我的理解：把公共的方法抽取出来，大家共用。 Spring默认使用JDK动态代理来创建AOP代理，" />
<meta property="og:type" content="article" />
<meta property="og:url" content="https://rulerLwx.gitee.io/2020/07/java-framework-spring-6-aop/" />
<meta property="article:published_time" content="2020-07-01T18:58:47+08:00" />
<meta property="article:modified_time" content="2020-07-01T18:58:47+08:00" />
<meta itemprop="name" content="Java-framework-Spring-6-AOP">
<meta itemprop="description" content="AOP AOP(Aspect Orient Programming)，面向切面编程。 我的理解：把公共的方法抽取出来，大家共用。 Spring默认使用JDK动态代理来创建AOP代理，">
<meta itemprop="datePublished" content="2020-07-01T18:58:47&#43;08:00" />
<meta itemprop="dateModified" content="2020-07-01T18:58:47&#43;08:00" />
<meta itemprop="wordCount" content="8653">



<meta itemprop="keywords" content="" /><meta name="twitter:card" content="summary"/>
<meta name="twitter:title" content="Java-framework-Spring-6-AOP"/>
<meta name="twitter:description" content="AOP AOP(Aspect Orient Programming)，面向切面编程。 我的理解：把公共的方法抽取出来，大家共用。 Spring默认使用JDK动态代理来创建AOP代理，"/>

    <!--[if lte IE 9]>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/classlist/1.1.20170427/classList.min.js"></script>
      <![endif]-->

    <!--[if lt IE 9]>
        <script src="https://cdn.jsdelivr.net/npm/html5shiv@3.7.3/dist/html5shiv.min.js"></script>
        <script src="https://cdn.jsdelivr.net/npm/respond.js@1.4.2/dest/respond.min.js"></script>
      <![endif]-->
  </head>

  
  

  <body class="main-center theme-black" itemscope itemtype="http://schema.org/WebPage"><header class="header" itemscope itemtype="http://schema.org/WPHeader">
    <div class="slimContent">
      <div class="navbar-header">
        <div class="profile-block text-center">
          <a id="avatar" href="https://gitee.com/rulerLwx" target="_blank">
            <img class="img-circle img-rotate" src="https://rulerLwx.gitee.io/avatar.png" width="200" height="200">
          </a>
          <h2 id="name" class="hidden-xs hidden-sm">rulerLwx</h2>
          <h3 id="title" class="hidden-xs hidden-sm hidden-md">thinking...</h3>
          <small id="location" class="text-muted hidden-xs hidden-sm"><i class="icon icon-map-marker"></i>Guangzhou, China</small>
        </div><div class="search" id="search-form-wrap">
    <form class="search-form sidebar-form">
        <div class="input-group">
            <input type="text" class="search-form-input form-control" placeholder="Search" />
            <span class="input-group-btn">
                <button type="submit" class="search-form-submit btn btn-flat" onclick="return false;"><i
                        class="icon icon-search"></i></button>
            </span>
        </div>
        <div class="ins-search">
            <div class="ins-search-mask"></div>
            <div class="ins-search-container">
                <div class="ins-input-wrapper">
                    <input type="text" class="ins-search-input" placeholder="Type something..."
                        x-webkit-speech />
                    <button type="button" class="close ins-close ins-selectable" data-dismiss="modal"
                        aria-label="Close"><span aria-hidden="true">×</span></button>
                </div>
                <div class="ins-section-wrapper">
                    <div class="ins-section-container"></div>
                </div>
            </div>
        </div>
    </form>
</div>
        <button class="navbar-toggle collapsed" type="button" data-toggle="collapse" data-target="#main-navbar" aria-controls="main-navbar" aria-expanded="false">
          <span class="sr-only">Toggle navigation</span>
          <span class="icon-bar"></span>
          <span class="icon-bar"></span>
          <span class="icon-bar"></span>
        </button>
      </div>
      <nav id="main-navbar" class="collapse navbar-collapse" itemscope itemtype="http://schema.org/SiteNavigationElement" role="navigation">
        <ul class="nav navbar-nav main-nav">
            <li class="menu-item menu-item-home">
                <a href="/">
                    <i class="icon icon-home-fill"></i>
                  <span class="menu-title">Home</span>
                </a>
            </li>
            <li class="menu-item menu-item-archives">
                <a href="/posts/">
                    <i class="icon icon-archives-fill"></i>
                  <span class="menu-title">Archives</span>
                </a>
            </li>
            <li class="menu-item menu-item-categories">
                <a href="/categories/">
                    <i class="icon icon-folder"></i>
                  <span class="menu-title">Categories</span>
                </a>
            </li>
            <li class="menu-item menu-item-tags">
                <a href="/tags/">
                    <i class="icon icon-tags"></i>
                  <span class="menu-title">Tags</span>
                </a>
            </li>
            <li class="menu-item menu-item-about">
                <a href="/about/">
                    <i class="icon icon-cup-fill"></i>
                  <span class="menu-title">About</span>
                </a>
            </li>
        </ul>
      </nav>
    </div>
  </header>

<aside class="sidebar" itemscope itemtype="http://schema.org/WPSideBar">
  <div class="slimContent">
    
      <div class="widget">
    <h3 class="widget-title">Board</h3>
    <div class="widget-body">
        <div id="board">
            <div class="content">enjoy~
            </div>
        </div>
    </div>
</div>

      <div class="widget">
    <h3 class="widget-title"> Categories</h3>
    <div class="widget-body">
        <ul class="category-list">
            <li class="category-list-item"><a href="https://rulerLwx.gitee.io/categories/java-framework/" class="category-list-link">java-framework</a><span class="category-list-count">38</span></li>
            <li class="category-list-item"><a href="https://rulerLwx.gitee.io/categories/java-front-end/" class="category-list-link">java-front-end</a><span class="category-list-count">11</span></li>
            <li class="category-list-item"><a href="https://rulerLwx.gitee.io/categories/java-se/" class="category-list-link">java-se</a><span class="category-list-count">21</span></li>
            <li class="category-list-item"><a href="https://rulerLwx.gitee.io/categories/java-senior/" class="category-list-link">java-senior</a><span class="category-list-count">4</span></li>
            <li class="category-list-item"><a href="https://rulerLwx.gitee.io/categories/linux/" class="category-list-link">linux</a><span class="category-list-count">13</span></li>
            <li class="category-list-item"><a href="https://rulerLwx.gitee.io/categories/tools/" class="category-list-link">tools</a><span class="category-list-count">1</span></li>
            <li class="category-list-item"><a href="https://rulerLwx.gitee.io/categories/%E6%8A%80%E6%9C%AF%E6%9D%82%E7%83%A9/" class="category-list-link">技术杂烩</a><span class="category-list-count">4</span></li>
            <li class="category-list-item"><a href="https://rulerLwx.gitee.io/categories/%E6%95%B0%E6%8D%AE%E5%BA%93/" class="category-list-link">数据库</a><span class="category-list-count">15</span></li>
        </ul>
    </div>
</div>
      <div class="widget">
    <h3 class="widget-title"> Tags</h3>
    <div class="widget-body">
        <ul class="tag-list">
            
            
            <li class="tag-list-item"><a href="https://rulerLwx.gitee.io/tags/jvm/" class="tag-list-link">jvm</a><span
                    class="tag-list-count">1</span></li>
            
            
            <li class="tag-list-item"><a href="https://rulerLwx.gitee.io/tags/%E5%A4%9A%E7%BA%BF%E7%A8%8B/" class="tag-list-link">多线程</a><span
                    class="tag-list-count">2</span></li>
            
            
            <li class="tag-list-item"><a href="https://rulerLwx.gitee.io/tags/%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B/" class="tag-list-link">网络编程</a><span
                    class="tag-list-count">3</span></li>
            
        </ul>

    </div>
</div>
      
<div class="widget">
    <h3 class="widget-title">Recent Posts</h3>
    <div class="widget-body">
        <ul class="recent-post-list list-unstyled no-thumbnail">
            <li>
                <div class="item-inner">
                    <p class="item-title">
                        <a href="https://rulerLwx.gitee.io/2020/07/%E8%87%AA%E5%B7%B1%E5%8A%A8%E6%89%8B%E4%B8%80%E6%89%B9%E9%87%8F%E7%A7%BB%E5%8A%A8%E9%87%8D%E5%91%BD%E5%90%8D%E6%96%87%E4%BB%B6/" class="title">自己动手（一）——批量移动、重命名文件</a>
                    </p>
                    <p class="item-date">
                        <time datetime="2020-07-27 17:50:02 &#43;0800 CST" itemprop="datePublished">2020-07-27</time>
                    </p>
                </div>
            </li>
            <li>
                <div class="item-inner">
                    <p class="item-title">
                        <a href="https://rulerLwx.gitee.io/2020/07/%E5%85%B3%E4%BA%8Einteger%E7%9A%84-128~127%E7%BC%93%E5%AD%98/" class="title">关于Integer的 -128~127缓存</a>
                    </p>
                    <p class="item-date">
                        <time datetime="2020-07-11 16:56:21 &#43;0800 CST" itemprop="datePublished">2020-07-11</time>
                    </p>
                </div>
            </li>
            <li>
                <div class="item-inner">
                    <p class="item-title">
                        <a href="https://rulerLwx.gitee.io/2020/07/%E8%B7%A8%E5%9F%9F%E9%97%AE%E9%A2%98/" class="title">跨域问题</a>
                    </p>
                    <p class="item-date">
                        <time datetime="2020-07-08 22:41:12 &#43;0800 CST" itemprop="datePublished">2020-07-08</time>
                    </p>
                </div>
            </li>
            <li>
                <div class="item-inner">
                    <p class="item-title">
                        <a href="https://rulerLwx.gitee.io/2020/07/%E4%B8%AA%E4%BA%BA%E5%8D%9A%E5%AE%A2%E6%90%AD%E5%BB%BA/" class="title">个人博客搭建</a>
                    </p>
                    <p class="item-date">
                        <time datetime="2020-07-05 18:58:47 &#43;0800 CST" itemprop="datePublished">2020-07-05</time>
                    </p>
                </div>
            </li>
            <li>
                <div class="item-inner">
                    <p class="item-title">
                        <a href="https://rulerLwx.gitee.io/2020/07/centos/" class="title">CentOS-</a>
                    </p>
                    <p class="item-date">
                        <time datetime="2020-07-01 18:58:47 &#43;0800 CST" itemprop="datePublished">2020-07-01</time>
                    </p>
                </div>
            </li>
        </ul>
    </div>
</div>
  </div>
</aside>

    
    
<aside class="sidebar sidebar-toc collapse" id="collapseToc" itemscope itemtype="http://schema.org/WPSideBar">
  <div class="slimContent">
    <h4 class="toc-title">Catalogue</h4>
    <nav id="toc" class="js-toc toc">

    </nav>
  </div>
</aside>
<main class="main" role="main"><div class="content">
  <article id="-" class="article article-type-" itemscope
    itemtype="http://schema.org/BlogPosting">
    
    <div class="article-header">
      <h1 itemprop="name">
  <a
    class="article-title"
    href="/2020/07/java-framework-spring-6-aop/"
    >Java-framework-Spring-6-AOP</a
  >
</h1>

      <div class="article-meta">
        
<span class="article-date">
  <i class="icon icon-calendar-check"></i>&nbsp;
<a href="https://rulerLwx.gitee.io/2020/07/java-framework-spring-6-aop/" class="article-date">
  <time datetime="2020-07-01 18:58:47 &#43;0800 CST" itemprop="datePublished">2020-07-01</time>
</a>
</span>
<span class="article-category">
  <i class="icon icon-folder"></i>&nbsp;
  <a class="article-category-link" href="/categories/java-framework/"> Java-framework </a>
</span>

        <span class="post-comment"><i class="icon icon-comment"></i>&nbsp;<a href="/2020/07/java-framework-spring-6-aop/#comments"
            class="article-comment-link">Comments</a></span>
		<span class="post-wordcount hidden-xs" itemprop="wordCount">Word Count: 8653words</span>
		<span class="post-readcount hidden-xs" itemprop="timeRequired">Read Count: 18minutes </span>
      </div>
    </div>
    <div class="article-entry marked-body js-toc-content" itemprop="articleBody">
      <h1 id="aop">AOP</h1>
<p>AOP(Aspect Orient Programming)，面向切面编程。</p>
<p>我的理解：把公共的方法抽取出来，大家共用。</p>
<p>Spring默认使用JDK动态代理来创建AOP代理，这样就可以为任何接口实例创建代理了。也可以使用cglib代理，在需要代理类而不是代理接口的时候，spring会自动切换到cglib代理。</p>
<p>JDK动态代理，被代理的类必须要实现有接口。cglib则不用。</p>
<p>Spring的AOP有两种实现方式：</p>
<ul>
<li>XML配置方式</li>
<li>Annotation注解方式</li>
</ul>
<h2 id="基本概念">基本概念</h2>
<ul>
<li>切面（Aspect）：用于组织多个Advice。可以理解为我们自定义的切面类。</li>
<li>连接点（Joinpoint）：可以理解为一串表达式，如<code>&quot;execution(* org.crazyit.app.servie.impl.*.*(..))&quot;</code>。</li>
<li>增强处理（Advice）：在特定的切入点执行的增强处理。如“before”、“after”。</li>
<li>切入点（Pointcut）：可以插入增强处理的连接点。当被增强处理时，连接点就变成切入点。</li>
</ul>
<p>可以理解为：连接点是一种抽象描述，切入点是一个具体描述。</p>
<p>即：连接点是一串表达式，其中可以匹配很多方法；切入点，就是被增强时，只匹配一个方法。</p>
<h2 id="注解方式实现aop">注解方式实现AOP</h2>
<p>JDK1.5才提供的注解，所以，低于1.5的就不能使用注解方式。</p>
<h3 id="基本使用步骤">基本使用步骤</h3>
<p>1、添加jar包</p>
<pre><code>&lt;dependency&gt;
	&lt;groupId&gt;org.springframework&lt;/groupId&gt;
	&lt;artifactId&gt;spring-aop&lt;/artifactId&gt;
	&lt;version&gt;${spring.version}&lt;/version&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
	&lt;groupId&gt;org.aspectj&lt;/groupId&gt;
	&lt;artifactId&gt;aspectjrt&lt;/artifactId&gt;
	&lt;version&gt;${aspectj.version}&lt;/version&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
	&lt;groupId&gt;org.aspectj&lt;/groupId&gt;
	&lt;artifactId&gt;aspectjweaver&lt;/artifactId&gt;
	&lt;version&gt;${aspectj.version}&lt;/version&gt;
&lt;/dependency&gt;
</code></pre>
<p>2、定义切面，并在切面里写好切入点、增强处理等等</p>
<pre><code>// 定义一个切面
@Aspect
public class AuthAspect{
	// 匹配org.crazyit.app.service.impl包下所有类的、
	// 所有方法的执行作为切入点
	@Before(&quot;execution(* org.crazyit.app.service.impl.*.*(..))&quot;)
	public void authority(){
		System.out.println(&quot;模拟执行权限检查&quot;);
	}
}
</code></pre>
<p>3、配置applicationContext.xml</p>
<pre><code>&lt;?xml version=&quot;1.0&quot; encoding=&quot;GBK&quot;?&gt;
&lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;
	xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
	xmlns:context=&quot;http://www.springframework.org/schema/context&quot;
	xmlns:aop=&quot;http://www.springframework.org/schema/aop&quot;
	xsi:schemaLocation=&quot;http://www.springframework.org/schema/beans 
	http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
	http://www.springframework.org/schema/context
	http://www.springframework.org/schema/context/spring-context-4.0.xsd
	http://www.springframework.org/schema/aop
	http://www.springframework.org/schema/aop/spring-aop-4.0.xsd&quot;&gt;
	&lt;!-- 指定自动搜索Bean组件、自动搜索切面类 --&gt;
	&lt;context:component-scan base-package=&quot;org.crazyit.app.service,org.crazyit.app.aspect&quot;&gt;
		&lt;context:include-filter type=&quot;annotation&quot; expression=&quot;org.aspectj.lang.annotation.Aspect&quot;/&gt;
	&lt;/context:component-scan&gt;
	
	&lt;!-- 启动@AspectJ支持 --&gt;
	&lt;aop:aspectj-autoproxy/&gt;
&lt;/beans&gt;

</code></pre>
<p>在配置文件中做两个配置：</p>
<p>1）开启aspectj注解功能：<code>&lt;aop:aspectj-autoproxy/&gt;</code></p>
<p>2）自动扫描业务bean和切面（可以扫描多个包，用逗号隔开）：<code>&lt;context:component-scan base-package=&quot;org.crazyit.app.service, org.crazyit.app.aspect&quot;&gt;</code>，默认并不会加载Aspect注解，因此，要include这个Aspect注解。</p>
<p>4、测试</p>
<pre><code>public class BeanTest{
	public static void main(String[] args){
		ApplicationContext ctx = new ClassPathXmlApplicationContext(&quot;beans.xml&quot;);
		Hello hello = ctx.getBean(&quot;hello&quot; , Hello.class);
		hello.foo();
		hello.addUser(&quot;孙悟空&quot; , &quot;7788&quot;);
		World world = ctx.getBean(&quot;world&quot; , World.class);
		world.bar();

	}
}
</code></pre>
<p>注意：要用接口来接收代理对象（面向接口编程）。</p>
<h3 id="各种增强处理的配置">各种增强处理的配置</h3>
<p>先要清楚各种通知的执行顺序或时机，如下：</p>
<pre><code>	//此处：前置通知	@Before
	
	public String getPersonName(){
		try {
			
			//此处执行业务方法
			
		} catch (Exception e) {
			
			//此处：异常通知	@AfterThrowing
			
			e.printStackTrace();
		}
		return null;
		
		//此处：返回通知	@AfterReturning
	}
	
	//此处：后置通知	@After
</code></pre>
<h4 id="before增强处理">Before增强处理</h4>
<p><code>@Before(&quot;execution(* org.crazyit.app.service.impl.*.*(..))&quot;)</code></p>
<p>使用@Before修饰时，通常需要指定一个value属性值，该属性值指定一个切入点表达式（既可以是一个已有的切入点，也可以直接定义切入点表达式），用于指定该增强处理将被织入哪些切入点。</p>
<p>如果是已有的切入点，则写法如下：</p>
<pre><code>@Aspect
public class MyAspect {
	@Pointcut(&quot;execution(* com.demo.service.impl.*.*(..))&quot;)
	private void myPointCut(){}
	
	@Before(&quot;myPointCut()&quot;)
	public void authority(){
		System.out.println(&quot;权限检查&quot;);
	}

}
</code></pre>
<h4 id="afterreturning增强处理">AfterReturning增强处理</h4>
<p>@AfterReturning注解可指定如下两个常用属性：</p>
<ul>
<li>pointcut/value：这两个属性的作用是一样的，都用于指定该切入点对应的切入表达式（既可以是一个已有的切入点，也可以直接定义切入点表达式）。当指定了pointcut值后，vlaue值将被覆盖。</li>
<li>returning：该属性指定一个形参名，用于表示Advice方法中可定义与此同名的形参，该形参可用于访问目标方法（业务bean中定义的方法）的返回值。除此之外，在Adice方法中定义该形参（代表上档方法的返回值）时指定的类型，会限制目标方法必须返回指定类型的值或没有返回值。</li>
</ul>
<p>示例：</p>
<pre><code>public interface Hello{
	void foo();
	int addUser(String name , String pass);
}
</code></pre>
<pre><code>public interface World{
	public void bar();
}
</code></pre>
<pre><code>@Component(&quot;hello&quot;)
public class HelloImpl implements Hello{
	public void foo(){
		System.out.println(&quot;执行Hello组件的foo()方法&quot;);
	}
	public int addUser(String name , String pass){
		System.out.println(&quot;执行Hello组件的addUser添加用户：&quot; + name);
		if(name.length() &lt; 3 || name.length() &gt; 10){
			throw new IllegalArgumentException(&quot;name参数的长度必须大于3，小于10！&quot;);
		}
		return 20;
	}
}
</code></pre>
<pre><code>@Component(&quot;world&quot;)
public class WorldImpl implements World{
	public void bar()	{
		System.out.println(&quot;执行World组件的bar()方法&quot;);
	}
}
</code></pre>
<pre><code>// 定义一个切面
@Aspect
public class LogAspect{
	// 声明rvt时指定的类型会限制目标方法必须返回指定类型的值或没有返回值
	// 此处将rvt的类型声明为Object，意味着对目标方法的返回值不加限制
	@AfterReturning(returning=&quot;rvt&quot;, pointcut=&quot;execution(* org.crazyit.app.service.impl.*.*(..))&quot;)
	public void log(Object rvt){
		System.out.println(&quot;获取目标方法返回值:&quot; + rvt);
		System.out.println(&quot;模拟记录日志功能...&quot;);
	}
}
</code></pre>
<pre><code>&lt;?xml version=&quot;1.0&quot; encoding=&quot;GBK&quot;?&gt;
&lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;
	xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
	xmlns:context=&quot;http://www.springframework.org/schema/context&quot;
	xmlns:aop=&quot;http://www.springframework.org/schema/aop&quot;
	xsi:schemaLocation=&quot;http://www.springframework.org/schema/beans 
	http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
	http://www.springframework.org/schema/context
	http://www.springframework.org/schema/context/spring-context-4.0.xsd
	http://www.springframework.org/schema/aop
	http://www.springframework.org/schema/aop/spring-aop-4.0.xsd&quot;&gt;

	&lt;context:component-scan base-package=&quot;org.crazyit.app.service,org.crazyit.app.aspect&quot;&gt;
		&lt;context:include-filter type=&quot;annotation&quot; expression=&quot;org.aspectj.lang.annotation.Aspect&quot;/&gt;
	&lt;/context:component-scan&gt;
	
	&lt;aop:aspectj-autoproxy/&gt;
&lt;/beans&gt;
</code></pre>
<pre><code>public class BeanTest{
	public static void main(String[] args){
		// 创建Spring容器
		ApplicationContext ctx = new ClassPathXmlApplicationContext(&quot;beans.xml&quot;);
		Hello hello = ctx.getBean(&quot;hello&quot; , Hello.class);
		hello.foo();
		hello.addUser(&quot;悟空&quot; , &quot;7788&quot;);
		World world = ctx.getBean(&quot;world&quot; , World.class);
		world.bar();
	}
}
</code></pre>
<h4 id="afterthrowing增强处理">AfterThrowing增强处理</h4>
<p>@AfterThrowing主要用于处理程序中未处理的异常。可指定如下两个注解：</p>
<ul>
<li>pointcut/value：同上。</li>
<li>throwing：该属性指定一个形参名，用于表示Advice方法中可定义与此同名的形参，该形参可用于访问目标方法抛出的异常。除此外，会限制目标方法必须抛出指定类型的异常。</li>
</ul>
<pre><code>@Aspect
public class RepairAspect{
	@AfterThrowing(throwing=&quot;ex&quot;, pointcut=&quot;execution(* org.crazyit.app.service.impl.*.*(..))&quot;)
	// 声明ex时指定的类型会限制目标方法必须抛出指定类型的异常
	// 此处将ex的类型声明为Throwable，意味着对目标方法抛出的异常不加限制
	public void doRecoveryActions(Throwable ex){
		System.out.println(&quot;目标方法中抛出的异常:&quot; + ex);
		System.out.println(&quot;模拟Advice对异常的修复...&quot;);
	}
}
</code></pre>
<h4 id="after增强处理">After增强处理</h4>
<p>@After跟@Before对应，是必然会执行的（如果定义了此增强处理），不论一个方法是如何结束的（正常或异常）。</p>
<p>@After注解需要指定一个value属性，表示一个切入点（既可以是一个已有的切入点，也可以直接定义切入点表达式）。</p>
<pre><code>@Aspect
public class ReleaseAspect{
	@After(&quot;execution(* org.crazyit.app.service.*.*(..))&quot;)
	public void release(){
		System.out.println(&quot;模拟方法结束后的释放资源...&quot;);
	}
}
</code></pre>
<h4 id="around增强处理">Around增强处理</h4>
<p>@Around注解需要指定一个vlue属性，表示一个切入点。</p>
<p>@Around注解修饰的增强方法的第一个形参必须是ProceedingJoinPoint（至少包含一个形参），在Advice方法体内，调用ProceedingJoinPoint形参的processed()方法后才会执行目标方法。如下：</p>
<pre><code>	@Around(&quot;myPointCut()&quot;)
	public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
		
//		return pjp.proceed();
		
		return null;
		
	}
</code></pre>
<p>环绕通知相当于自定义通知。格式是固定的：Object ，ProceedingJoinPoint 。</p>
<p>特点：</p>
<p>1、如果 return null;则不会执行之后的方法；</p>
<p>2、如果 return pjp.proceed();则会执行之后的方法</p>
<p>3、我们可以通过pjp对象来判断让不让它执行之后的方法，以达到权限控制。</p>
<p>调用ProceedingJoinPoint形参的processed()方法时，还可以传一个Object[]对象作为参数，该数组中的值将被传入目标方法作为执行方法的实参。</p>
<pre><code>@Aspect
public class TxAspect{
	@Around(&quot;execution(* org.crazyit.app.service.impl.*.*(..))&quot;)
	public Object processTx(ProceedingJoinPoint jp) throws java.lang.Throwable {
	
		System.out.println(&quot;执行目标方法之前，模拟开始事务...&quot;);
		
		// 获取目标方法原始的调用参数
		Object[] args = jp.getArgs();
		if(args != null &amp;&amp; args.length &gt; 1){
			// 修改目标方法的第一个参数
			args[0] = &quot;【增加的前缀】&quot; + args[0];
		}
		
		// 以改变后的参数去执行目标方法，并保存目标方法执行后的返回值
		Object rvt = jp.proceed(args);
		System.out.println(&quot;执行目标方法之后，模拟结束事务...&quot;);
		
		// 如果rvt的类型是Integer，将rvt改为它的平方
		if(rvt != null &amp;&amp; rvt instanceof Integer)
			rvt = (Integer)rvt * (Integer)rvt;
		return rvt;
	}
}
</code></pre>
<h3 id="其它知识点">其它知识点</h3>
<h4 id="访问目标方法的参数">访问目标方法的参数</h4>
<p>访问目标方法最简单的做法是定义增强处理方法时将第一个参数定义为JoinPoint类型。当增强处理方法被调用时，该JoinPoint参数就代表了织入增强处理的连接点。</p>
<p>JoinPoint里包含如下几个常用的方法：</p>
<ul>
<li>Object[] getArgs()：返回执行目标方法时的参数。</li>
<li>Signature getSignature()：返回被增加方法的相关信息。</li>
<li>Object getTarget()：返回被织入增强处理的目标对象。</li>
<li>Object getThis()：返回AOP框架为目标对象生成的代理对象。</li>
</ul>
<p>注：@Around注解修饰的增强方法的第一个形参ProceedingJoinPoint是JoinPoint的子类。</p>
<p>示例：</p>
<pre><code>@Aspect
public class FourAdviceTest{

	@Around(&quot;execution(* org.crazyit.app.service.impl.*.*(..))&quot;)
	public Object processTx(ProceedingJoinPoint jp) throws java.lang.Throwable {
		System.out.println(&quot;Around增强：执行目标方法之前，模拟开始事务...&quot;);
		// 访问执行目标方法的参数
		Object[] args = jp.getArgs();
		// 当执行目标方法的参数存在，
		// 且第一个参数是字符串参数
		if (args != null &amp;&amp; args.length &gt; 0
			&amp;&amp; args[0].getClass() == String.class)
		{
			// 修改目标方法调用参数的第一个参数
			args[0] = &quot;【增加的前缀】&quot; + args[0];
		}
		//执行目标方法，并保存目标方法执行后的返回值
		Object rvt = jp.proceed(args);
		System.out.println(&quot;Around增强：执行目标方法之后，模拟结束事务...&quot;);
		// 如果rvt的类型是Integer，将rvt改为它的平方
		if(rvt != null &amp;&amp; rvt instanceof Integer)
			rvt = (Integer)rvt * (Integer)rvt;
		return rvt;
	}
	
	// 定义Before增强处理
	@Before(&quot;execution(* org.crazyit.app.service.impl.*.*(..))&quot;)
	public void authority(JoinPoint jp) {
		System.out.println(&quot;Before增强：模拟执行权限检查&quot;);
		// 返回被织入增强处理的目标方法
		System.out.println(&quot;Before增强：被织入增强处理的目标方法为：&quot; + jp.getSignature().getName());
		// 访问执行目标方法的参数
		System.out.println(&quot;Before增强：目标方法的参数为：&quot; + Arrays.toString(jp.getArgs()));
		// 访问被增强处理的目标对象
		System.out.println(&quot;Before增强：被织入增强处理的目标对象为：&quot; + jp.getTarget());
	}
	
	//定义AfterReturning增强处理
	@AfterReturning(pointcut=&quot;execution(* org.crazyit.app.service.impl.*.*(..))&quot;, returning=&quot;rvt&quot;)
	public void log(JoinPoint jp , Object rvt){
		System.out.println(&quot;AfterReturning增强：获取目标方法返回值:&quot;+ rvt);
		System.out.println(&quot;AfterReturning增强：模拟记录日志功能...&quot;);
		// 返回被织入增强处理的目标方法
		System.out.println(&quot;AfterReturning增强：被织入增强处理的目标方法为：&quot;+ jp.getSignature().getName());
		// 访问执行目标方法的参数
		System.out.println(&quot;AfterReturning增强：目标方法的参数为：&quot; + Arrays.toString(jp.getArgs()));
		// 访问被增强处理的目标对象
		System.out.println(&quot;AfterReturning增强：被织入增强处理的目标对象为：&quot;+ jp.getTarget());
	}

	// 定义After增强处理
	@After(&quot;execution(* org.crazyit.app.service.impl.*.*(..))&quot;)
	public void release(JoinPoint jp) {
		System.out.println(&quot;After增强：模拟方法结束后的释放资源...&quot;);
		// 返回被织入增强处理的目标方法
		System.out.println(&quot;After增强：被织入增强处理的目标方法为：&quot; + jp.getSignature().getName());
		// 访问执行目标方法的参数
		System.out.println(&quot;After增强：目标方法的参数为：&quot; + Arrays.toString(jp.getArgs()));
		// 访问被增强处理的目标对象
		System.out.println(&quot;After增强：被织入增强处理的目标对象为：&quot; + jp.getTarget());
	}
}
</code></pre>
<p>另外一个访问目标方法的参数的方法是：在程序中使用args切入点表达式来绑定目标方法的参数。args中声明有多少个参数，则目标方法中也要声明有多少个参数才能正确被匹配。如：<code>&quot;execution(* org.crazyit.app.service.impl.*.*(..)) &amp;&amp; args(arg0,arg1)&quot;</code>，arg0和arg1的类型由增强方法决定，如增强方式的入参是<code>access(String arg0 , String arg1)</code>，则arg0和arg1的类型都是String。</p>
<p>示例：</p>
<pre><code>@Aspect
public class AccessArgAspect{
	// 下面的args(arg0,arg1)会限制目标方法必须有2个形参
	@AfterReturning(returning=&quot;rvt&quot; , pointcut=&quot;execution(* org.crazyit.app.service.impl.*.*(..)) &amp;&amp; args(arg0,arg1)&quot;)
	// 此处指定arg0、arg1为String类型
	// 则args(arg0,arg1)还要求目标方法的两个形参都是String类型
	public void access(Object rvt, String arg0 , String arg1)
	{
		System.out.println(&quot;调用目标方法第1个参数为:&quot; + arg0);
		System.out.println(&quot;调用目标方法第2个参数为:&quot; + arg1);
		System.out.println(&quot;获取目标方法返回值:&quot; + rvt);
		System.out.println(&quot;模拟记录日志功能...&quot;);
	}
}
</code></pre>
<p>如何控制同一连接点织入的优先顺序呢？方法有二：</p>
<p>1）让切面实现org.springframework.core.Ordered接口，int getOrder()返回的值越小，则优先级越高。</p>
<p>2）直接使用@Order注解来修饰一个切面类，指定一个int型的vlaue值，值越小，优先级越高。</p>
<h4 id="定义切入点">定义切入点</h4>
<p>定义切入点的意义是，让不同的增强处理共用一个切入点。</p>
<p>切入点的定义通常包括两个部分：</p>
<p>1）一个切入点表达式。</p>
<p>2）一个包含名字和任意参数的方法签名。</p>
<p>注意：切入点的方法签名的方法体通常为空，返回值类型必须是void；切入点表达式用@Pointcut来标注。如下：</p>
<pre><code>	@Pointcut(&quot;execution(* com.demo.service.impl.*.*(..))&quot;)
	private void myPointCut(){}
</code></pre>
<p>可以引用其它类中定义好的切入点，格式：类名.切入点方法名()，如下：pointcut=&quot;SystemArchitecture.myPointcut()&quot;。</p>
<p>示例：</p>
<pre><code>@Aspect
public class SystemArchitecture{
	@Pointcut(&quot;execution(* org.crazyit.app.service.impl.*.*(..))&quot;)
	public void myPointcut(){}
}
</code></pre>
<pre><code>@Aspect
public class LogAspect{
	// 直接使用SystemArchitecture切面类的myPointcut()切入点
	@AfterReturning(returning=&quot;rvt&quot;, pointcut=&quot;SystemArchitecture.myPointcut()&quot;)
	// 声明rvt时指定的类型会限制目标方法必须返回指定类型的值或没有返回值
	// 此处将rvt的类型声明为Object，意味着对目标方法的返回值不加限制
	public void log(Object rvt)
	{
		System.out.println(&quot;获取目标方法返回值:&quot; + rvt);
		System.out.println(&quot;模拟记录日志功能...&quot;);
	}
}
</code></pre>
<h4 id="切入指示符">切入指示符</h4>
<p>前面大量使用到的execution表达式，就是一个切入点指示符。除execution外，spring还支持如下几种切入点指示符：</p>
<ul>
<li>within：todo&hellip;.</li>
<li>this：</li>
<li>target：</li>
<li>args：对连接点的参数类型进行限制</li>
<li>bean：</li>
</ul>
<h4 id="组合切入点表达式">组合切入点表达式</h4>
<p>spring支持如下切入点表达式：</p>
<ul>
<li>&amp;&amp;：要求切入同时匹配两个切入点表达式</li>
<li>||：匹配任意一个</li>
<li>!：不匹配给出的切入点表达式</li>
</ul>
<p>前面有过下面这种写法，就是组合切入点表达式了：</p>
<p><code>pointcut= &quot;execution(* org.crazyit.app.service.impl.*.*(..)) &amp;&amp; args(arg0,arg1)&quot;</code>。</p>
<h2 id="xml方式实现aop">XML方式实现AOP</h2>
<p>所有的切面、切入点和增强处理都必须定义在<a href="aop:config.../">aop:config.../</a>元素内部。&lt;beans&hellip;/&gt;元素下可以包含多个<a href="aop:config.../">aop:config.../</a>元素，一个<a href="aop:config.../">aop:config.../</a>元素可以包含pointcut、advisor、aspect元素（且这三个元素必须按此顺序来定义），其中aspect下可以包含多个子元素（且元素无序）——通过使用这些元素就可以在XML文件中配置切面、切入点和增强处理了。一个<a href="aop:config.../">aop:config.../</a>元素可以有多个<a href="aop:aspectj.../">aop:aspectj.../</a>元素。</p>
<p><a href="aop:config.../">aop:config.../</a>元素所包含的子元素如下：</p>
<pre><code class="language-xml">&lt;aop:config&gt;
	&lt;aop:pointcut expression=&quot;&quot; id=&quot;&quot;/&gt;	// a	全局切入点
	&lt;aop:advisor advice-ref=&quot;&quot;/&gt;	// b	全局增强处理，配置事务时用到
	&lt;aop:aspect id=&quot;&quot; ref=&quot;&quot;&gt;	// c
		&lt;aop:pointcut expression=&quot;&quot; id=&quot;&quot;/&gt;
		&lt;aop:declare-parents types-matching=&quot;&quot; implement-interface=&quot;&quot;/&gt;
		&lt;aop:before method=&quot;&quot;/&gt;
		&lt;aop:after method=&quot;&quot;/&gt;
		&lt;aop:after-throwing method=&quot;&quot;/&gt;
		&lt;aop:after-returning method=&quot;&quot;/&gt;
		&lt;aop:around method=&quot;&quot;/&gt;
	&lt;/aop:aspect&gt;
&lt;/aop:config&gt;
</code></pre>
<p>注意：a、b、c的顺序不能颠倒。a、b是全局切入点、增强处理，可以不定义a、b，但要在c中定义。</p>
<p>另外，使用<a href="aop:config.../">aop:config.../</a>方式进行配置时，可能与Spring的自动代理方式相冲突。例如使用<a href="aop:aspectj-autoproxy.../">aop:aspectj-autoproxy.../</a>或类似方式显式启用自动代理，则可能出现此问题。因此建议：要么全部使用<a href="aop:config.../">aop:config.../</a>配置方式，要么全部使用自动代理方式，不要两者混合使用。</p>
<p>示例：</p>
<pre><code>public class FourAdviceTest{
	public Object processTx(ProceedingJoinPoint jp) throws java.lang.Throwable {
		System.out.println(&quot;Around增强：执行目标方法之前，模拟开始事务...&quot;);
		// 访问执行目标方法的参数
		Object[] args = jp.getArgs();
		// 当执行目标方法的参数存在，
		// 且第一个参数是字符串参数
		if (args != null &amp;&amp; args.length &gt; 0
			&amp;&amp; args[0].getClass() == String.class)
		{
			// 修改目标方法调用参数的第一个参数
			args[0] = &quot;【增加的前缀】&quot; + args[0];
		}
		//执行目标方法，并保存目标方法执行后的返回值
		Object rvt = jp.proceed(args);
		System.out.println(&quot;Around增强：执行目标方法之后，模拟结束事务...&quot;);
		// 如果rvt的类型是Integer，将rvt改为它的平方
		if(rvt != null &amp;&amp; rvt instanceof Integer)
			rvt = (Integer)rvt * (Integer)rvt;
		return rvt;
	}
	
	public void authority(JoinPoint jp) {
		System.out.println(&quot;②Before增强：模拟执行权限检查&quot;);
		// 返回被织入增强处理的目标方法
		System.out.println(&quot;②Before增强：被织入增强处理的目标方法为：&quot; + jp.getSignature().getName());
		// 访问执行目标方法的参数
		System.out.println(&quot;②Before增强：目标方法的参数为：&quot; + Arrays.toString(jp.getArgs()));
		// 访问被增强处理的目标对象
		System.out.println(&quot;②Before增强：被织入增强处理的目标对象为：&quot; + jp.getTarget());
	}
	
	public void log(JoinPoint jp , Object rvt) {
		System.out.println(&quot;AfterReturning增强：获取目标方法返回值:&quot; + rvt);
		System.out.println(&quot;AfterReturning增强：模拟记录日志功能...&quot;);
		// 返回被织入增强处理的目标方法
		System.out.println(&quot;AfterReturning增强：被织入增强处理的目标方法为：&quot; + jp.getSignature().getName());
		// 访问执行目标方法的参数
		System.out.println(&quot;AfterReturning增强：目标方法的参数为：&quot; + Arrays.toString(jp.getArgs()));
		// 访问被增强处理的目标对象
		System.out.println(&quot;AfterReturning增强：被织入增强处理的目标对象为：&quot; + jp.getTarget());
	}
	public void release(JoinPoint jp){
		System.out.println(&quot;After增强：模拟方法结束后的释放资源...&quot;);
		// 返回被织入增强处理的目标方法
		System.out.println(&quot;After增强：被织入增强处理的目标方法为：&quot;+ jp.getSignature().getName());
		// 访问执行目标方法的参数
		System.out.println(&quot;After增强：目标方法的参数为：&quot;+ Arrays.toString(jp.getArgs()));
		// 访问被增强处理的目标对象
		System.out.println(&quot;After增强：被织入增强处理的目标对象为：&quot;+ jp.getTarget());
	}
}
</code></pre>
<pre><code>public class SecondAdviceTest{
	public void authority(String aa){
		System.out.println(&quot;目标方法的参数为：&quot; + aa);
		System.out.println(&quot;①号Before增强：模拟执行权限检查&quot;);
	}
}
</code></pre>
<pre><code>&lt;?xml version=&quot;1.0&quot; encoding=&quot;GBK&quot;?&gt;
&lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;
	xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
	xmlns:aop=&quot;http://www.springframework.org/schema/aop&quot;
	xsi:schemaLocation=&quot;http://www.springframework.org/schema/beans 
	http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
	http://www.springframework.org/schema/aop
	http://www.springframework.org/schema/aop/spring-aop-4.0.xsd&quot;&gt;
	&lt;aop:config&gt;
		&lt;!-- 将fourAdviceBean转换成切面Bean 切面Bean的新名称为：fourAdviceAspect 指定该切面的优先级为2 --&gt;
		&lt;aop:aspect id=&quot;fourAdviceAspect&quot; ref=&quot;fourAdviceBean&quot; order=&quot;2&quot;&gt;
			&lt;!-- 定义一个After增强处理， 直接指定切入点表达式 以切面Bean中的release()方法作为增强处理方法 --&gt;
			&lt;aop:after pointcut=&quot;execution(* org.crazyit.app.service.impl.*.*(..))&quot; method=&quot;release&quot;/&gt;
			&lt;!-- 定义一个Before增强处理，直接指定切入点表达式 以切面Bean中的authority()方法作为增强处理方法 --&gt;
			&lt;aop:before pointcut=&quot;execution(* org.crazyit.app.service.impl.*.*(..))&quot; method=&quot;authority&quot;/&gt;
			&lt;!-- 定义一个AfterReturning增强处理，直接指定切入点表达式 以切面Bean中的log()方法作为增强处理方法 --&gt;
			&lt;aop:after-returning pointcut=&quot;execution(* org.crazyit.app.service.impl.*.*(..))&quot; method=&quot;log&quot; returning=&quot;rvt&quot;/&gt;
			&lt;!-- 定义一个Around增强处理，直接指定切入点表达式 以切面Bean中的processTx()方法作为增强处理方法 --&gt;
			&lt;aop:around pointcut=&quot;execution(* org.crazyit.app.service.impl.*.*(..))&quot;  method=&quot;processTx&quot;/&gt;
		&lt;/aop:aspect&gt;

		&lt;!-- 将secondAdviceBean转换成切面Bean 切面Bean的新名称为：secondAdviceAspect 指定该切面的优先级为1，该切面里的增强处理将被优先织入 --&gt;
		&lt;aop:aspect id=&quot;secondAdviceAspect&quot; ref=&quot;secondAdviceBean&quot; order=&quot;1&quot;&gt;
			&lt;!-- 定义一个Before增强处理， 直接指定切入点表达式 以切面Bean中的authority()方法作为增强处理方法  且该参数必须为String类型（由authority方法声明中msg参数的类型决定） --&gt;
			&lt;aop:before pointcut= &quot;execution(* org.crazyit.app.service.impl.*.*(..)) and args(aa)&quot;  method=&quot;authority&quot;/&gt;
		&lt;/aop:aspect&gt;
	&lt;/aop:config&gt;

	&lt;bean id=&quot;fourAdviceBean&quot; class=&quot;org.crazyit.app.aspect.FourAdviceTest&quot;/&gt;
	&lt;bean id=&quot;secondAdviceBean&quot; class=&quot;org.crazyit.app.aspect.SecondAdviceTest&quot;/&gt;
	&lt;bean id=&quot;hello&quot; class=&quot;org.crazyit.app.service.impl.HelloImpl&quot;/&gt;
	&lt;bean id=&quot;world&quot; class=&quot;org.crazyit.app.service.impl.WorldImpl&quot;/&gt;
&lt;/beans&gt;
</code></pre>
<p>总结：其实&lt;aop:aspect ref=””&hellip;/&gt;就是我们定义好的切面（也就是注解方式时使用@Aspect的那个类），其子元素（如before）中的method指向我们定义的切面中的方法名。</p>

    </div>
    <div class="article-footer">
<blockquote class="mt-2x">
  <ul class="post-copyright list-unstyled">
    <li class="post-copyright-link hidden-xs">
      <strong>Permalink: </strong>
      <a href="https://rulerLwx.gitee.io/2020/07/java-framework-spring-6-aop/" title="Java-framework-Spring-6-AOP" target="_blank" rel="external">https://rulerLwx.gitee.io/2020/07/java-framework-spring-6-aop/</a>
    </li>
    <li class="post-copyright-license">
      <strong>License：</strong><a href="http://creativecommons.org/licenses/by/4.0/deed.zh" target="_blank" rel="external">CC BY 4.0 CN</a>
    </li>
  </ul>
</blockquote>

<div class="panel panel-default panel-badger">
  <div class="panel-body">
    <figure class="media">
      <div class="media-left">
        <a href="https://gitee.com/rulerLwx" target="_blank" class="img-burn thumb-sm visible-lg">
          <img src="https://rulerLwx.gitee.io/avatar.png" class="img-rounded w-full" alt="">
        </a>
      </div>
      <div class="media-body">
        <h3 class="media-heading"><a href="https://gitee.com/rulerLwx" target="_blank"><span class="text-dark">rulerLwx</span><small class="ml-1x">thinking...</small></a></h3>
        <div>Good Good Study, Day Day Up~</div>
      </div>
    </figure>
  </div>
</div>
    </div>
  </article>
<section id="comments">
    <div id="vcomments"></div>
</section>

</div><nav class="bar bar-footer clearfix" data-stick-bottom>
    <div class="bar-inner">
        <ul class="pager pull-left">
            <li class="prev">
                <a href="https://rulerLwx.gitee.io/2020/07/java-framework-spring-7-%E4%BA%8B%E5%8A%A1/" title="Java-framework-Spring-7-事务"><i
                        class="icon icon-angle-left"
                        aria-hidden="true"></i><span>&nbsp;&nbsp;Older</span></a>
            </li>
            <li class="next">
                <a href="https://rulerLwx.gitee.io/2020/07/java-framework-spring-5-%E8%AE%BF%E9%97%AE%E8%B5%84%E6%BA%90/"
                    title="Java-framework-Spring-5-访问资源"><span>Newer&nbsp;&nbsp;</span><i
                        class="icon icon-angle-right" aria-hidden="true"></i></a>
            </li>
            
            <li class="toggle-toc">
                <a class="toggle-btn collapsed" data-toggle="collapse" href="#collapseToc" aria-expanded="false"
                    title="Catalogue" role="button">
                    <span>[&nbsp;</span><span>Catalogue</span>
                    <i class="text-collapsed icon icon-anchor"></i>
                    <i class="text-in icon icon-close"></i>
                    <span>]</span>
                </a>
            </li>
        </ul>
        <div class="bar-right">
            <div class="share-component" data-sites="weibo,qq,wechat"
                data-mobile-sites="weibo,qq,qzone"></div>
        </div>
    </div>
</nav>

</main><footer class="footer" itemscope itemtype="http://schema.org/WPFooter">
<ul class="social-links">
    <li><a href="https://gitee.com/rulerLwx" target="_blank" title="gitee" data-toggle=tooltip data-placement=top >
            <i class="icon icon-gitee"></i></a></li>
    <li><a href="https://github.com/wolf-lea" target="_blank" title="github" data-toggle=tooltip data-placement=top >
            <i class="icon icon-github"></i></a></li>
</ul>
  <div class="copyright">
    &copy;2020  -
    2020
    <div class="publishby">
        Theme by <a href="https://github.com/xiaoheiAh" target="_blank"> xiaoheiAh </a>base on<a href="https://github.com/xiaoheiAh/hugo-theme-pure" target="_blank"> pure</a>.
    </div>
  </div>
</footer>

<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.2/MathJax.js?config=TeX-MML-AM_SVG"></script>
<script type="text/x-mathjax-config">
    MathJax.Hub.Config({
            showMathMenu: false, //disables context menu
            tex2jax: {
            inlineMath: [ ['$','$'], ['\\(','\\)'] ]
           }
    });
</script>


<script src="https://cdn.jsdelivr.net/npm/jquery@3.4.1/dist/jquery.min.js"></script>
<script>
    window.jQuery || document.write('<script src="js/jquery.min.js"><\/script>')
</script>
<script type="text/javascript" src="https://cdn.staticfile.org/highlight.js/9.15.10/highlight.min.js"></script>
<script type="text/javascript" src="https://cdn.staticfile.org/highlight.js/9.15.10/languages/python.min.js" defer></script>
<script type="text/javascript" src="https://cdn.staticfile.org/highlight.js/9.15.10/languages/javascript.min.js" defer></script><script>
    hljs.configure({
        tabReplace: '    ', 
        classPrefix: ''     
        
    })
    hljs.initHighlightingOnLoad();
</script>
<script src="https://rulerLwx.gitee.io/js/application.min.bdeb64b910570b6c41badc6a05b7afb0c8ad9efd8525de3c7257d59e786326a3.js"></script>
<script src="https://rulerLwx.gitee.io/js/plugin.min.51ff8c7317566f82259170fa36e09c4493adc9b9378b427a01ad3f017ebac7dd.js"></script>

<script>
    (function (window) {
        var INSIGHT_CONFIG = {
            TRANSLATION: {
                POSTS: 'Posts',
                PAGES: 'Pages',
                CATEGORIES: 'Categories',
                TAGS: 'Tags',
                UNTITLED: '(Untitled)',
            },
            ROOT_URL: 'https:\/\/rulerLwx.gitee.io',
            CONTENT_URL: 'https:\/\/rulerLwx.gitee.io\/searchindex.json ',
        };
        window.INSIGHT_CONFIG = INSIGHT_CONFIG;
    })(window);
</script>
<script type="text/javascript" src="https://rulerLwx.gitee.io/js/insight.min.a343cd9a5a7698336b28ef3a7c16a3a1b1d2d5fb17dc8ed04022bbe08cc5459073a15bdafa3a8a58cdd56080784bdd69fa70b1ae8597565c799c57ed00f0e120.js" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tocbot/4.4.2/tocbot.min.js"></script>
<script>
    tocbot.init({
        
        tocSelector: '.js-toc',
        
        contentSelector: '.js-toc-content',
        
        headingSelector: 'h1, h2, h3',
        
        hasInnerContainers: true,
    });
</script>

<script src="https://cdn1.lncld.net/static/js/3.0.4/av-min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/valine"></script>
<script type="text/javascript">
    var GUEST = ['nick', 'mail', 'link'];
    var meta = 'nick,mail';
    meta = meta.split(',').filter(function (item) {
        return GUEST.indexOf(item) > -1;
    });
    new Valine({
        el: '#vcomments',
        verify: null ,
        notify: null ,
        appId: 'IyAB0PSPRazTPDxitO1ddQ7O-gzGzoHsz',
        appKey: '5rBJTq4KidYF33eXwvRVhtEH',
        placeholder: 'enjoy~',
        avatar: 'mm',
        meta: meta,
        pageSize: '10' || 10,
        visitor: false 
});
</script>

  </body>
</html>
